package com.zj.service;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.PutObjectRequest;
import com.zj.config.OssConfig;
import com.zj.util.FileTypeValidator;
import lombok.extern.java.Log;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

/**
 * 文件上传并且去重服务
 * 先去重再上传
 */
@Service
@Log   //springboot 默认的日志框架是 logback
public class FileDeduplicationService {
    private static final String REDIS_IMAGE_MD5_PREFIX = "image:md5:";  //前缀
    private static final long REDIS_KEY_TTL_DAYS=30*12;  //在redis中存储的时间，单位是天

    @Autowired
    private OssConfig ossConfig;
    @Autowired
    private OSS ossClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public String processAndGetFileUrl(MultipartFile file) throws IOException {
        String contentType=file.getContentType();  //文件的MIME类型
        String originalFilename=file.getOriginalFilename(); //原始的文件名
        if(!FileTypeValidator.isAllowedFileType(contentType,originalFilename)){
            throw new IllegalArgumentException("文件类型不支持"+originalFilename);
        }
        String md5Hash; //文件的MD5值
        try(InputStream is=file.getInputStream()){  //将文件内容转换为输入流
            md5Hash= DigestUtils.md5Hex(is);    //对文件内容进行MD5计算  这样即使文件名不同，内容相同也会是同一个MD5，内容不同，文件名相同，不是同一个MD5
        }catch (IOException e){
            log.severe("无法计算文件的md5码"+originalFilename);
            throw new RuntimeException("无法计算文件的md5码"+originalFilename,e);
        }

        //到redis中检查是否有MD5值
        String redisKey=REDIS_IMAGE_MD5_PREFIX+md5Hash;
        String fileUrl=stringRedisTemplate.opsForValue().get(redisKey);
        if(fileUrl!=null && !fileUrl.isEmpty()){
            log.info("检测到重复md5"+md5Hash+"文件已存在，直接返回URL"+fileUrl);
            stringRedisTemplate.expire(redisKey,REDIS_KEY_TTL_DAYS, TimeUnit.DAYS);
            return fileUrl;
        }
        log.info("新文件的md5"+md5Hash+"上传到OSS");

        //真正上传到OSS
        String FileExtension= "";
        if (originalFilename!=null && originalFilename.contains(".")){
            FileExtension=originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        //新上传的文件名：md5码+后缀名
        String objectKey="files/"+md5Hash+FileExtension;  //上传成功后的地址 files:/md5码.后缀名
        PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), objectKey, file.getInputStream());
        ossClient.putObject(putObjectRequest);
        //拼接上传成功后的路径
        String newFileUrl=ossConfig.getUrlPrefix()+ File.separator+objectKey;
//        String newFileUrl=ossConfig.getUrlPrefix()+"/"+objectKey;
        //将MD5码和新的URL存储到redis中
        this.stringRedisTemplate.opsForValue().set(redisKey,newFileUrl,REDIS_KEY_TTL_DAYS, TimeUnit.DAYS);
        log.info("文件上传成功，地址为"+newFileUrl+"redis中MD5码为"+redisKey);
        return newFileUrl;
    }

}
